首页/ 学科题库/ webgl/ WebGL 视图矩阵与透视投影配置
webgl 实战教程

WebGL 视图矩阵与透视投影配置

2026-09-13 约 8 分钟 juanwangdev

WebGL 视图矩阵与透视投影配置

一句话结论:视图矩阵决定从哪看,投影矩阵决定看到多大范围和多深,两者与模型矩阵相乘构成完整的 MVP 变换。

视图矩阵与相机位置

是什么

视图矩阵把世界坐标系中的顶点转换到以相机为原点的相机坐标系。它由相机的位置、注视目标与上方向共同决定,是相机在世界变换的逆变换。

解决什么问题

它解决视角控制问题。场景中所有物体的顶点都存放在世界坐标里,要呈现"从某个位置看过去"的画面,就必须把整个场景按相机的相对位姿反向变换,让相机在变换后位于原点并朝向固定方向。

为什么这样做

移动相机与移动整个世界在数学上是等价的,但后者不需要修改任何物体数据。GPU 只需在顶点着色器里多乘一个矩阵,就能实现自由视角、第一人称漫游与轨道观察,成本极低。

怎么用

JavaScript
// lookAt:相机位置、注视点、上方向
const view = mat4.create();
mat4.lookAt(view,
  [eyeX, eyeY, eyeZ],   // 相机位置
  [0, 0, 0],            // 注视目标
  [0, 1, 0]             // 上方向
);

// 轨道相机:用球坐标算相机位置再 lookAt
const r = 5, theta = 0.8, phi = 1.2;
const eye = [
  r * Math.sin(phi) * Math.cos(theta),
  r * Math.cos(phi),
  r * Math.sin(phi) * Math.sin(theta),
];
mat4.lookAt(view, eye, [0, 0, 0], [0, 1, 0]);
glsl
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
void main() {
  gl_Position = uProjection * uView * uModel * vec4(aPosition, 1.0);
}

常见坑

  • 把视图矩阵当成"相机位置"直接写入 → 原因:两者不是同一概念 → 处理:用 lookAt 由位置与目标生成矩阵
  • 相机看向正上方导致画面翻转 → 原因:上方向与视线平行 → 处理:限制俯仰角,避免接近正负 90 度
  • 每帧改变上方向造成画面抖动 → 原因:上方向参与正交化计算 → 处理:轨道相机固定使用世界 Y 轴
  • 修改相机后忘记重算矩阵 → 原因:矩阵是快照 → 处理:相机参数变化后重新调用 lookAt

透视投影矩阵配置

是什么

透视投影矩阵把相机坐标系下的顶点映射到裁剪空间,并写入深度信息。配置参数是垂直视场角 fovy、宽高比 aspect、近平面 near 与远平面 far,四者共同决定画面视野、纵深范围与深度精度。

解决什么问题

它解决"三维场景如何变成二维画面"的问题。视场角决定能看多宽,宽高比保证画面比例正确,两个裁剪面剔除过近与过远的物体,同时把 z 值压缩到 -1 到 1 的裁剪区间供深度测试使用。

为什么这样做

人眼观察世界是透视的,平行线在远处汇聚,因此三维画面必须模拟这种收缩。投影矩阵通过把 w 分量设为与视空间 z 相关的值,让 GPU 的透视除法自动产生近大远小的效果,无需在着色器中手写缩放逻辑。

怎么用

JavaScript
const fovy = 45 * Math.PI / 180;   // 垂直视场角,常用 45~60 度
const aspect = canvas.width / canvas.height;
const near = 0.1;                  // 尽量取大一些,提升深度精度
const far = 100;

const projection = mat4.create();
mat4.perspective(projection, fovy, aspect, near, far);
gl.uniformMatrix4fv(uProjection, false, projection);
参数取值建议影响
fovy45°–60°过大画面畸变,过小像长焦
aspect缓冲宽 / 缓冲高不匹配画面被拉伸
near尽量大(如 0.1–1)越小近处越精确但远处精度下降
far覆盖场景即可过大会浪费深度精度

常见坑

  • 用 CSS 尺寸计算 aspect → 原因:应使用渲染缓冲尺寸 → 处理:用 canvas.width/height 计算
  • near 设为 0 或极小值 → 原因:透视除法会发散且深度精度崩溃 → 处理:near 必须大于 0 并尽量取大
  • near 与 far 跨度过大 → 原因:深度值非线性分布 → 处理:压缩 far,或对远景使用对数深度
  • 窗口变化后画面变形 → 原因:投影矩阵未重算 → 处理:尺寸变化时同步重建投影矩阵与视口

要点总结

  • 视图矩阵是相机变换的逆,用 lookAt 由位置、目标与上方向生成
  • 投影矩阵四参数:视场角、宽高比、近平面、远平面
  • aspect 必须用渲染缓冲尺寸计算,尺寸变化要重算矩阵与视口
  • near 不能为 0,且应与 far 保持合理比例以保证深度精度
  • MVP 顺序固定为投影 × 视图 × 模型,顺序写反画面会错乱

常见问题

视图矩阵和相机位置有什么关系?

视图矩阵是相机世界变换的逆矩阵。相机在世界中的移动与旋转反过来作用于所有物体,等价于把相机固定在原点看向负 z 方向,因此修改视图矩阵就等于移动相机。

透视投影需要配置哪些参数?

四个参数:垂直视场角 fovy、画布宽高比 aspect、近裁剪面 near、远裁剪面 far。视场角决定视野大小,宽高比保证画面不变形,两个裁剪面决定可见的纵深范围。

为什么物体穿模或深度闪烁?

多半是近远平面比例过大。深度缓冲精度集中靠近平面,near 太小或 far 太大都会让远处深度值失去分辨力,调整时应尽量拉近 near、压缩 far。

画布拉伸变形是什么原因?

宽高比没有跟随画布更新。投影矩阵的 aspect 必须等于渲染缓冲宽度除以高度,窗口或设备像素比变化后要重新计算投影矩阵。

想在手机上练这篇的配套题目?
使用微信 卷王开发者小程序/App,首页顶部扫一扫识别下方二维码,即可解锁本讲对应真题与错题本。
了解产品 App
← 上一篇 WebGL 齐次坐标与模型矩阵变换 下一篇 → WebGL 正交投影与法线矩阵